<template>
  <div>
    <div class="q-pa-md" style="max-width: 500px">
      <div class="q-gutter-md">
        <q-input
          v-model="cableSegment"
          label="输入故障光缆段"
          debounce="500"
          filled
          :placeholder="defaultInput"
        >
          <template v-slot:append>
            <q-icon @click="searchOpticalFiberCable()" name="search"></q-icon>
          </template>
        </q-input>
      </div>
    </div>
    <div class="q-pa-md">
      <q-table
        title="故障影响范围预测表"
        :loading="loadingState"
        :data="data"
        :columns="columns"
        row-key="id"
      />
    </div>
    <div
      class="q-pa-md q-gutter-sm"
      style="display: flex; justify-content: flex-end"
    >
      <q-btn
        class="btn-fixed-width"
        color="primary"
        label="导出"
        @click="exportData()"
      />
      <q-btn
        class="btn-fixed-width"
        color="secondary"
        label="图谱推理"
        @click="showKnowledgeGraph()"
      />
    </div>

    <!-- 添加知识图谱对话框 -->
    <q-dialog v-model="showDialog" full-width>
      <q-card class="full-width">
        <q-card-section class="row items-center q-pb-none">
          <div class="text-h6">知识图谱</div>
          <q-space />
          <q-btn
            v-if="canGoBack"
            icon="arrow_back"
            flat
            round
            dense
            class="q-mr-md"
            @click="goBack"
            title="返回上一级"
          />
          <q-btn icon="close" flat round dense v-close-popup />
        </q-card-section>

        <q-card-section>
          <div id="knowledge-graph" style="width: 100%; height: 600px;"></div>
        </q-card-section>
      </q-card>
    </q-dialog>
  </div>
</template>

<script>
import { exportFile } from "quasar";
import axios from "axios";
import * as XLSX from "xlsx";

export default {
  data() {
    return {
      defaultInput: "",
      cableSegment: "",
      loadingState: false,
      showDialog: false,
      force: null,
      svg: null,
      visibleColumns: [
        "故障光缆段",
        "故障纤芯",
        "影响的光路",
        "影响的纤芯通道",
        "影响的业务",
      ],
      columns: [
        {
          name: "故障光缆段",
          label: "故障光缆段",
          align: "left",
          field: "故障光缆段",
        },
        {
          name: "故障纤芯",
          align: "center",
          label: "故障纤芯",
          field: "故障纤芯",
        },
        {
          name: "影响的光路",
          label: "影响的光路",
          field: "影响的光路",
        },
        {
          name: "影响的纤芯通道",
          label: "影响的纤芯通道",
          field: "影响的纤芯通道",
        },
        {
          name: "影响的业务",
          label: "影响的业务",
          field: "影响的业务",
        },
      ],
      data: [],
      currentGraphData: {
        nodes: [],
        links: []
      },
      nodeHistory: [],
    };
  },
  computed: {
    canGoBack() {
      return this.nodeHistory.length > 0;
    }
  },
  mounted() {
    this.loadD3().catch(error => {
      console.error('加载D3失败:', error);
    });
  },
  created() {
    this.initializeData();
  },
  methods: {
    initializeData() {
      try {
        const renderData = JSON.parse(localStorage.getItem("链路") || "[]");
        if (renderData.length > 0) {
          const maxFaultItem = renderData.reduce((max, current) => {
            return (current.故障分析值 > max.故障分析值) ? current : max;
          }, renderData[0]);

          this.defaultInput = maxFaultItem.所属光缆段;
          this.cableSegment = maxFaultItem.所属光缆段;

          this.searchOpticalFiberCable();
        }
      } catch (error) {
        console.error("初始化数据失败:", error);
      }
    },
    exportData() {
      const worksheet = XLSX.utils.json_to_sheet(this.data, {
        header: this.visibleColumns,
      });
      const workbook = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");

      const now = new Date();
      const year = now.getFullYear();
      const month = String(now.getMonth() + 1).padStart(2, "0"); // 月份从0开始，所以加1，并确保两位数
      const day = String(now.getDate()).padStart(2, "0"); // 日期
      const hours = String(now.getHours()).padStart(2, "0"); // 小时
      const minutes = String(now.getMinutes()).padStart(2, "0"); // 分钟
      const seconds = String(now.getSeconds()).padStart(2, "0"); // 秒数
      XLSX.writeFile(
        workbook,
        `结果数据集_${year}${month}${day}${hours}${minutes}${seconds}.xlsx`
      );
    },
    changeLoadingState() {
      this.loadingState = !this.loadingState;
    },
    async searchOpticalFiberCable() {
      this.changeLoadingState();
      this.data.splice(0, this.data.length);
      try {
        const response = await axios.post('http://localhost:4444/get_cable_segment_data', {
          cable_segment: this.cableSegment
        });

        // 检查响应格式并获取结果数据
        const result = response.data.data;

        // 筛选有yw_名称字段，且不包含"必填"和"设备0"的数据
        const filteredResult1 = result.filter(item => {
          return item["yw_名称"] &&
                 !item["yw_名称"].includes("必填") &&
                 !item["yw_名称"].includes("设备0");
        });

        // 筛选对应纤芯通道不为空的数据,并将备注字段赋值给yw_名称字段
        const filteredResult2 = result.filter(item => {
          if (item["对应纤芯通道"]) {
            item["yw_名称"] = item["备注"];
            return true;
          }
          return false;
        });

        // 合并两个数据集
        const filteredResult = [...filteredResult1, ...filteredResult2];

        this.data = [...new Set(filteredResult.map((item) => {
          return JSON.stringify({
            故障光缆段: item["所属光缆段"],
            故障纤芯: item["简称"],
            影响的光路: item["对应光路"],
            影响的纤芯通道: item["对应纤芯通道"],
            影响的业务: item["yw_名称"],
          });
        }))].map(item => JSON.parse(item));
      } catch (error) {
        console.log(error);
      }
      this.changeLoadingState();
    },
    async showKnowledgeGraph() {
      try {
        this.showDialog = true;
        this.nodeHistory = [];
        await this.$nextTick();

        await new Promise(resolve => setTimeout(resolve, 100));

        this.initializeGraphData();
        await this.initializeD3Graph();
      } catch (error) {
        console.error('显示知识图谱失败:', error);
      }
    },
    initializeGraphData() {
      try {
        const nodes = [];
        const links = [];

        if (this.data.length > 0) {
          const firstRow = this.data[0];

          // 添加根节点
          const rootNode = {
            id: "故障光缆段",
            name: "故障光缆段",
            level: 0
          };
          nodes.push(rootNode);

          // 添加光缆段节点
          const cableNode = {
            id: firstRow.故障光缆段,
            name: firstRow.故障光缆段,
            level: 1
          };
          nodes.push(cableNode);

          // 添加连接
          links.push({
            source: 0,
            target: 1,
            relation: "所属光缆段"
          });

          // 移除第三级节点的初始化
          // 不再添加光路节点和其连接

          this.currentGraphData = {
            nodes: nodes,
            links: links
          };

          // 存储到 localStorage
          localStorage.setItem('knowledgeData', JSON.stringify(this.currentGraphData));
        }
      } catch (error) {
        console.error('初始化图谱数据失败:', error);
      }
    },
    async initializeD3Graph() {
      try {
        const d3 = await this.loadD3();
        if (!d3) {
          throw new Error('D3 未加载');
        }

        const container = document.getElementById("knowledge-graph");
        if (!container) {
          throw new Error('找不到图谱容器');
        }

        // 清除现有内容
        container.innerHTML = '';

        const width = container.clientWidth;
        const height = 600;

        // 创建新的 SVG 元素
        d3.select("#knowledge-graph")
          .append("svg")
          .attr("width", width)
          .attr("height", height);

        // 初始化力导向图
        this.force = d3.layout.force()
          .size([width, height])
          .linkDistance(200)
          .charge(-2000);

        if (this.currentGraphData.nodes.length > 0) {
          await this.$nextTick();
          await this.updateGraph(this.currentGraphData);
        }
      } catch (error) {
        console.error('初始化D3图谱失败:', error);
      }
    },
    async updateGraph(graphData) {
      try {
        const d3 = await this.loadD3();
        if (!graphData || !this.force || !d3) {
          throw new Error('更新图谱所需的依赖不完整');
        }

        // 确保数据格式正确
        if (!Array.isArray(graphData.nodes) || !Array.isArray(graphData.links)) {
          throw new Error('图谱数据格式不正确');
        }

        // 清除现有内容并重新创建 SVG
        const svg = d3.select("#knowledge-graph svg");
        svg.selectAll("*").remove();

        // 添加箭头定义
        const defs = svg.append("defs");
        defs.selectAll("marker")
          .data(["end"])
          .enter().append("marker")
          .attr("id", String)
          .attr("viewBox", "0 -5 10 10")
          .attr("refX", 25)
          .attr("refY", 0)
          .attr("markerWidth", 6)
          .attr("markerHeight", 6)
          .attr("orient", "auto")
          .append("path")
          .attr("d", "M0,-5L10,0L0,5")
          .style("fill", "#666");

        // 更新力导向图数据
        this.force
          .nodes(graphData.nodes)
          .links(graphData.links)
          .start();

        // 绘制连线和文本
        const linkGroup = svg.selectAll(".link-group")
          .data(graphData.links)
          .enter()
          .append("g")
          .attr("class", "link-group");

        // 添加连线
        linkGroup.append("line")
          .attr("class", "link")
          .style("stroke", "#666")
          .style("stroke-width", 1.5)
          .style("stroke-dasharray", "5,5")
          .attr("marker-end", "url(#end)");

        // 添加连线文本（修改这部分）
        linkGroup.append("text")
          .attr("class", "link-text")
          .text(d => d.relation);

        // 绘制节点
        const node = svg.selectAll(".node")
          .data(graphData.nodes)
          .enter()
          .append("g")
          .attr("class", "node")
          .call(this.force.drag)
          .on("click", (d) => this.handleNodeClick(d));

        node.append("circle")
          .attr("r", 12)
          .style("fill", (d) => this.getNodeColor(d.level));

        node.append("text")
          .attr("dx", 15)
          .attr("dy", ".35em")
          .attr("class", "node-text")
          .text(d => this.formatNodeText(d.name));

        // 修改 force.on("tick") 部分
        this.force.on("tick", () => {
          // 更新连线
          linkGroup.selectAll("line")
            .attr("x1", d => d.source.x)
            .attr("y1", d => d.source.y)
            .attr("x2", d => {
              const dx = d.target.x - d.source.x;
              const dy = d.target.y - d.source.y;
              const dr = Math.sqrt(dx * dx + dy * dy);
              return d.target.x - (dx * 10) / dr;
            })
            .attr("y2", d => {
              const dx = d.target.x - d.source.x;
              const dy = d.target.y - d.source.y;
              const dr = Math.sqrt(dx * dx + dy * dy);
              return d.target.y - (dy * 10) / dr;
            });

          // 更新连线文本位置（修改这部分）
          linkGroup.selectAll("text")
            .attr("x", d => (d.source.x + d.target.x) / 2)
            .attr("y", d => (d.source.y + d.target.y) / 2 - 10); // 向上偏移10像素

          // 更新节点位置
          node.attr("transform", d => `translate(${d.x},${d.y})`);
        });
      } catch (error) {
        console.error('更新图谱失败:', error);
      }
    },
    handleNodeClick(node, isGoingBack = false) {
      try {
        console.log('点击节点:', {
          id: node.id,
          name: node.name,
          level: node.level
        });

        if (!isGoingBack && this.currentGraphData.nodes.length > 0) {
          this.nodeHistory.push(this.currentGraphData.nodes[0]);
        }

        const nodes = [];
        const links = [];
        const addedNodeIds = new Set();

        // 添加当前节点
        nodes.push({
          id: node.id,
          name: node.name,
          level: node.level
        });
        addedNodeIds.add(node.id);

        if (node.level === 0) {
          // 点击根节点，展示所有光缆段
          console.log('点击根节点，展示所有光缆段');
          const uniqueCables = [...new Set(this.data.map(item => item.故障光缆段))];

          uniqueCables.forEach((cableName) => {
            if (!addedNodeIds.has(cableName)) {
              nodes.push({
                id: cableName,
                name: cableName,
                level: 1
              });
              addedNodeIds.add(cableName);
              links.push({
                source: 0,
                target: nodes.length - 1,
                relation: "所属光缆段"
              });
            }
          });
        } else if (node.level === 1) {
          // 点击光缆段节点，展示相关光路
          console.log('点击光缆段节点，展示相关光路');
          const relatedPaths = [...new Set(
            this.data
              .filter(item => item.故障光缆段 === node.name)
              .map(item => item.影响的光路)
          )];

          relatedPaths.forEach((path) => {
            if (!addedNodeIds.has(path)) {
              nodes.push({
                id: path,
                name: path,
                level: 2
              });
              addedNodeIds.add(path);
              links.push({
                source: 0,
                target: nodes.length - 1,
                relation: "对应光路"
              });
            }
          });
        } else if (node.level === 2) {
          // 点击光路节点，展示相关业务
          console.log('点击光路节点，展示相关业务');
          const relatedServices = [...new Set(
            this.data
              .filter(item => item.影响的光路 === node.name)
              .map(item => item.影响的业务)
          )];

          relatedServices.forEach((service) => {
            if (!addedNodeIds.has(service)) {
              nodes.push({
                id: service,
                name: service,
                level: 3
              });
              addedNodeIds.add(service);
              links.push({
                source: 0,
                target: nodes.length - 1,
                relation: "业务名称"
              });
            }
          });
        } else if (node.level === 3) {
          // 点击业务节点，显示对应的光路节点
          console.log('点击业务节点，显示对应的光路');
          const relatedPath = this.data.find(item => item.影响的业务 === node.name);
          if (relatedPath) {
            // 添加光路节点
            nodes.push({
              id: relatedPath.影响的光路,
              name: relatedPath.影响的光路,
              level: 2
            });
            addedNodeIds.add(relatedPath.影响的光路);

            // 添加连接
            links.push({
              source: 0,
              target: 1,
              relation: "对应光路"
            });
          }
        }

        console.log('更新图谱数据:', {
          nodes: nodes,
          links: links
        });

        this.currentGraphData = { nodes, links };
        this.updateGraph(this.currentGraphData);
      } catch (error) {
        console.error('处理节点点击事件失败:', error);
      }
    },
    getNodeColor(level) {
      const colors = ['#ff7f0e', '#1f77b4', '#2ca02c', '#d62728'];
      return colors[level] || '#999';
    },
    formatNodeText(text) {
      return text || '';
    },
    loadD3() {
      return new Promise((resolve, reject) => {
        // 如果已经加载了D3直接返回
        if (window.d3) {
          resolve(window.d3);
          return;
        }

        // 如果已经存在script标签，不要重复添加
        if (document.querySelector('script[src*="d3.v3.min.js"]')) {
          const checkD3 = setInterval(() => {
            if (window.d3) {
              clearInterval(checkD3);
              resolve(window.d3);
            }
          }, 100);
          return;
        }

        const script = document.createElement('script');
        script.src = 'https://d3js.org/d3.v3.min.js';
        script.async = true;
        script.onload = () => {
          const checkD3 = setInterval(() => {
            if (window.d3) {
              clearInterval(checkD3);
              resolve(window.d3);
            }
          }, 100);
        };
        script.onerror = () => reject(new Error('Failed to load D3'));
        document.head.appendChild(script);
      });
    },
    goBack() {
      if (this.nodeHistory.length > 0) {
        const previousNode = this.nodeHistory.pop();
        this.handleNodeClick(previousNode, true);
      }
    },
  },
};
</script>

<style>
.btn-fixed-width {
  min-width: 100px;
}

.link {
  fill: none;
  stroke: #666;
  stroke-width: 1px;
  opacity: 0.8;
  stroke-dasharray: 5,5;
}

.node circle {
  fill: #ccc;
  stroke: #333;
  stroke-width: 1.5px;
  r: 12;
}

.node text {
  font: 12px Microsoft YaHei;
  pointer-events: none;
  text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}

.node-text {
  font-size: 12px;
  font-family: Microsoft YaHei;
  fill: #333;
  text-anchor: start;
  dx: 15;
}

/* 修改箭头样式 */
marker#end {
  fill: #666;
  stroke: none;
}

.link-text {
  font-size: 12px;
  fill: #666;
  text-anchor: middle;
  dominant-baseline: middle;
  pointer-events: none;
  background-color: white;
  padding: 2px;
}

.link-group {
  cursor: default;
}

/* 添加返回按钮样式 */
.back-button {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 1000;
}

.back-button:hover {
  background-color: rgba(0, 0, 0, 0.1);
}
</style>
